home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-wos-src / pasm / output_elf.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  15KB  |  461 lines

  1. /* $VER: pasm output_elf.c V1.2 (24.10.98)
  2.  *
  3.  * This file is part of pasm, a portable PowerPC assembler.
  4.  * Copyright (c) 1997-98  Frank Wille
  5.  *
  6.  * pasm is freeware and part of the portable and retargetable ANSI C
  7.  * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
  8.  * pasm may be freely redistributed as long as no modifications are
  9.  * made and nothing is charged for it. Non-commercial usage is allowed
  10.  * without any restrictions.
  11.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  12.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  13.  *
  14.  *
  15.  * v1.2   (24.10.98) phx
  16.  *        An empty section with reloc symbols will no longer be deleted.
  17.  * v1.1d  (27.09.97) phx
  18.  *        fopen() uses binary mode "b" for windoze/msdog compatibility.
  19.  * v1.0   (15.04.98) phx
  20.  *        The symbol's type was wrong. It was 'Object' for absolute symbols
  21.  *        and 'Function' for reloc symbols.
  22.  *        Allocated 1 byte too less, for ".rela.xxx" strings.
  23.  * v0.9   (03.04.98) phx
  24.  *        Reloc section header was corrupted on little endian machines.
  25.  *        WEAK symbols were generated, instead of GLOBAL ones!
  26.  * v0.5   (12.10.97) phx
  27.  *        Removed "pasm V0.x" from .comment section.
  28.  * v0.3   (10.04.97) phx
  29.  *        Fixed enforcer-hit, when external references are present.
  30.  *        Some vbcc-specific changes.
  31.  *        Support for little endian architectures.
  32.  * v0.2   (25.03.97) phx
  33.  *        Writes ELF object for 32-bit PowerPC big-endian. Either absolute
  34.  *        or ELF output format may be selected. ELF is default for all
  35.  *        currently supported platforms. PPCasm supports nine different
  36.  *        relocation types (there are much more...).
  37.  *        Compiles and works also under NetBSD/amiga (68k).
  38.  *        Changed function declaration to 'new style' in all sources
  39.  *        (to avoid problems with '...' for example).
  40.  *        File created.
  41.  */
  42.  
  43.  
  44. #define OUTPUT_ELF_C
  45. #include "ppcasm.h"
  46. #include "elf.h"
  47. #include <time.h>
  48.  
  49.  
  50. struct StrTabList {
  51.   struct list l;
  52.   uint32 index;
  53. };
  54.  
  55. struct StrTabNode {
  56.   struct node n;
  57.   char *str;
  58. };
  59.  
  60. struct ShdrNode {
  61.   struct node n;
  62.   struct Elf32_Shdr s;
  63. };
  64.  
  65. struct SymbolNode {
  66.   struct node n;
  67.   char *name;
  68.   struct Elf32_Sym s;
  69. };
  70.  
  71. struct RelaNode {
  72.   struct node n;
  73.   struct Elf32_Rela r;
  74. };
  75.  
  76.  
  77. static struct Elf32_Ehdr elf_header = {
  78.   { 0x7f,'E','L','F',ELFCLASS32,0,EV_CURRENT,0,0,0,0,0,0,0,0,0 },
  79.   ECH(ET_REL),ECH(EM_POWERPC),ECW(EV_CURRENT),0,0,0,0,
  80.   ECH(sizeof(struct Elf32_Ehdr)),
  81.   0,0,ECH(sizeof(struct Elf32_Shdr)),0,0
  82. };
  83. static char *output_name;
  84.  
  85.  
  86. void output_elf32msb(struct GlobalVars *);
  87.  
  88. static struct ShdrNode *addShdr(struct list *);
  89. static struct SymbolNode *addSymbol(struct list *,struct StrTabList *,char *);
  90. static uint32 addString(struct StrTabList *,char *);
  91. static void addRela(struct list *,uint32,uint32,uint32);
  92. static void fw(FILE *,void *,size_t);
  93.  
  94.  
  95.  
  96. void output_elf32msb(struct GlobalVars *gv)
  97. {
  98.   struct list shdrlist,symlist,relalist;
  99.   struct StrTabList shstrlist,strlist;
  100.   struct ShdrNode *shn;
  101.   struct SymbolNode *sym;
  102.   uint32 symtabidx,strtabidx,shstrtabidx,firstglobal,align1,align2;
  103.   uint32 roffset=0,soffset=sizeof(struct Elf32_Ehdr);
  104.   uint32 shdrindex=0,symindex=0;
  105.   struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
  106.   struct Symbol *symchain;
  107.   int i;
  108.   FILE *fp;
  109.  
  110.   /* init */
  111.   output_name = gv->dest_name;
  112.   elf_header.e_ident[EI_DATA] = ELFDATA2MSB;
  113.   initlist(&shdrlist);
  114.   initlist(&symlist);
  115.   initlist(&relalist);
  116.   shstrlist.index = strlist.index = 0;
  117.   initlist(&shstrlist.l);
  118.   initlist(&strlist.l);
  119.   addString(&shstrlist,"");  /* first string is always "" */
  120.   symtabidx = addString(&shstrlist,".symtab");
  121.   strtabidx = addString(&shstrlist,".strtab");
  122.   shstrtabidx = addString(&shstrlist,".shstrtab");
  123.   addShdr(&shdrlist);  /* first Shdr is always zero */
  124.   addString(&strlist,"");
  125.   addSymbol(&symlist,NULL,NULL);  /* first symbol table entry always empty */
  126.  
  127.   /* source file name symbol */
  128.   if (gv->file) {
  129.     ++symindex;
  130.     sym = addSymbol(&symlist,&strlist,gv->file);
  131.     sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_FILE);
  132.     sym->s.st_shndx = ECH(SHN_ABS);
  133.   }
  134.  
  135.   /* generate section headers for program sections */
  136.   while (nextsec = (struct Section *)sec->n.next) {
  137.     if (!(sec->flags & SF_DISCARD) &&
  138.         (sec->size > 0 || (sec->flags & SF_HASSYMS))) {
  139.       sec->index = ++shdrindex;
  140.       shn = addShdr(&shdrlist);
  141.       shn->s.sh_name = ECVW(addString(&shstrlist,sec->name));
  142.       if (sec->type==ST_UDATA || (sec->flags&SF_UNINITIALIZED))
  143.         shn->s.sh_type = ECW(SHT_NOBITS);
  144.       else
  145.         shn->s.sh_type = ECW(SHT_PROGBITS);
  146.       shn->s.sh_flags = ECW(SHF_ALLOC);
  147.       if (sec->protection & SP_WRITE)
  148.         shn->s.sh_flags |= ECW(SHF_WRITE);
  149.       if (sec->protection & SP_EXEC)
  150.         shn->s.sh_flags |= ECW(SHF_EXECINSTR);
  151.       shn->s.sh_offset = ECVW(soffset);
  152.       shn->s.sh_size = ECVW(sec->size);
  153.       if (shn->s.sh_type == ECW(SHT_PROGBITS))
  154.         soffset += sec->size;
  155.       shn->s.sh_addralign = ECVW(1<<(uint32)sec->alignment);
  156.       /* add section symbol */
  157.       sym = addSymbol(&symlist,NULL,NULL);
  158.       sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_SECTION);
  159.       sym->s.st_shndx = ECVH((uint16)shdrindex);
  160.       ++symindex;
  161.     }
  162.     sec = nextsec;
  163.   }
  164.  
  165.   /* comment section */
  166.   if (gv->ident || gv->vc) {
  167.     ++shdrindex;
  168.     shn = addShdr(&shdrlist);
  169.     shn->s.sh_name = ECVW(addString(&shstrlist,".comment"));
  170.     shn->s.sh_type = ECW(SHT_PROGBITS);
  171.     shn->s.sh_offset = ECVW(soffset);
  172.     shn->s.sh_size = 1;  /* zero-byte */
  173.     if (gv->ident)
  174.       shn->s.sh_size += (uint32)strlen(gv->ident)+1;
  175.     if (gv->vc)
  176.       shn->s.sh_size += 12;
  177.     soffset += shn->s.sh_size;
  178. #ifdef LITTLEENDIAN
  179.     shn->s.sh_size = l2bw(shn->s.sh_size);
  180. #endif
  181.     shn->s.sh_addralign = ECW(1);
  182.     /* add section symbol */
  183.     sym = addSymbol(&symlist,NULL,NULL);
  184.     sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_SECTION);
  185.     sym->s.st_shndx = ECVH((uint16)shdrindex);
  186.     ++symindex;
  187.   }
  188.  
  189.   /* build symbol table */
  190.   for (i=0; i<SYMHTABSIZE; i++) {  /* first, symbols with local binding */
  191.     symchain = gv->symbols[i];
  192.     while (symchain) {
  193.       if (*(symchain->name) != '.') {  /* '.symbols' are ignored */
  194.         if (symchain->type==SYM_ABS || symchain->type==SYM_RELOC) {
  195.           if (symchain->bind == SYMB_LOCAL) {
  196.             ++symindex;
  197.             sym = addSymbol(&symlist,&strlist,symchain->name);
  198.             sym->s.st_value = ECVW(symchain->value);
  199.             sym->s.st_size = ECVW(symchain->size);
  200.             sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,symchain->info);
  201.             if (symchain->type == SYM_ABS)
  202.               sym->s.st_shndx = ECH(SHN_ABS);
  203.             else
  204.               sym->s.st_shndx = ECVH((uint16)symchain->relsect->index);
  205.           }
  206.         }
  207.       }
  208.       symchain = symchain->hash_chain;
  209.     }
  210.   }
  211.   firstglobal = symindex + 1;
  212.   for (i=0; i<SYMHTABSIZE; i++) {  /* then, global and weak symbols */
  213.     symchain = gv->symbols[i];
  214.     while (symchain) {
  215.       if (*(symchain->name) != '.') {  /* '.symbols' are ignored */
  216.         if (symchain->type==SYM_ABS || symchain->type==SYM_RELOC) {
  217.           if (symchain->bind > SYMB_LOCAL) {
  218.             ++symindex;
  219.             sym = addSymbol(&symlist,&strlist,symchain->name);
  220.             sym->s.st_value = ECVW(symchain->value);
  221.             sym->s.st_size = ECVW(symchain->size);
  222.             sym->s.st_info = ELF32_ST_INFO(symchain->bind-SYMB_LOCAL,
  223.                                            symchain->info);
  224.             if (symchain->type == SYM_ABS)
  225.               sym->s.st_shndx = ECH(SHN_ABS);
  226.             else
  227.               sym->s.st_shndx = ECVH((uint16)symchain->relsect->index);
  228.           }
  229.         }
  230.       }
  231.       symchain = symchain->hash_chain;
  232.     }
  233.   }
  234.  
  235.   /* ".rela.xxx" relocation sections */
  236.   sec = (struct Section *)gv->sectionlist.first;
  237.   while (nextsec = (struct Section *)sec->n.next) {
  238.     if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
  239.       struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
  240.       struct XReference *nextxref;
  241.       struct XReference *xref=(struct XReference *)sec->xreflist.first;
  242.       uint32 ro=roffset;
  243.       char *sptr;
  244.  
  245.       while (nextrel = (struct Reloc *)rel->n.next) {
  246.         addRela(&relalist,rel->offset,rel->addend,
  247.                 ELF32_R_INFO(rel->relocsect->index,rel->type));
  248.         roffset += sizeof(struct Elf32_Rela);
  249.         rel = nextrel;
  250.       }
  251.  
  252.       while (nextxref = (struct XReference *)xref->n.next) {
  253.         struct SymbolNode *nextsym;
  254.         char *xname = xref->xsymbol->name;
  255.         uint32 sidx=0;
  256.  
  257.         /* check if referenced symbol is already in symbol table */
  258.         sym = (struct SymbolNode *)symlist.first;
  259.         while (nextsym = (struct SymbolNode *)sym->n.next) {
  260.           if (sym->name)
  261.             if (!strcmp(xname,sym->name))
  262.               break;
  263.           ++sidx;
  264.           sym = nextsym;
  265.         }
  266.         if (nextsym==NULL) {
  267.           sidx = ++symindex;
  268.           sym = addSymbol(&symlist,&strlist,xname);
  269.           sym->s.st_info = ELF32_ST_INFO(STB_GLOBAL,STT_NOTYPE);
  270.         }
  271.         addRela(&relalist,xref->offset,xref->addend,
  272.                 ELF32_R_INFO(sidx,xref->type));
  273.         roffset += sizeof(struct Elf32_Rela);
  274.         xref = nextxref;
  275.       }
  276.  
  277.       if (ro != roffset) {  /* were there any relocations? */
  278.         sptr = (char *)alloc(strlen(sec->name) + 6);
  279.         sprintf(sptr,".rela%s",sec->name);
  280.         ++shdrindex;
  281.         shn = addShdr(&shdrlist);
  282.         shn->s.sh_name = ECVW(addString(&shstrlist,sptr));
  283.         shn->s.sh_type = ECW(SHT_RELA);
  284.         shn->s.sh_offset = ro;  /* relative offset, corrected later */
  285.         shn->s.sh_size = ECVW(roffset - ro);
  286.         /* sh_link will be set later, when .symtab exists */
  287.         shn->s.sh_info = ECVW(sec->index); /* shdr idx to which reloc applies */
  288.         shn->s.sh_addralign = ECW(4);
  289.         shn->s.sh_entsize = ECW(sizeof(struct Elf32_Rela));
  290.       }
  291.     }
  292.     sec = nextsec;
  293.   }
  294.  
  295.   /* ".shstrtab" section header string table */
  296.   ++shdrindex;
  297.   shn = addShdr(&shdrlist);
  298.   shn->s.sh_name = ECVW(shstrtabidx);
  299.   shn->s.sh_type = ECW(SHT_STRTAB);
  300.   shn->s.sh_offset = ECVW(soffset);
  301.   shn->s.sh_size = ECVW(shstrlist.index);
  302.   shn->s.sh_addralign = ECW(1);
  303.   soffset += shstrlist.index;
  304.   align1 = ((soffset + 3) & ~3) - soffset;
  305.   soffset += align1;
  306.  
  307.   elf_header.e_shoff = ECVW(soffset);
  308.   soffset += (shdrindex+3)*sizeof(struct Elf32_Shdr);
  309.   elf_header.e_shstrndx = ECVH((uint16)shdrindex);
  310.   elf_header.e_shnum = ECVH((uint16)shdrindex+3);
  311.  
  312.   /* ".symtab" symbol table */
  313.   ++shdrindex;
  314.   ++symindex;  /* number of symbol in symbol table */
  315.   shn = addShdr(&shdrlist);
  316.   shn->s.sh_name = ECVW(symtabidx);
  317.   shn->s.sh_type = ECW(SHT_SYMTAB);
  318.   shn->s.sh_offset = ECVW(soffset);
  319.   shn->s.sh_size = symindex*sizeof(struct Elf32_Sym);
  320.   shn->s.sh_link = ECVW(shdrindex+1);  /* associated .strtab section */
  321.   shn->s.sh_info = ECVW(firstglobal);  /* first non-local symbol index */
  322.   shn->s.sh_addralign = ECW(4);
  323.   shn->s.sh_entsize = ECW(sizeof(struct Elf32_Sym));
  324.   soffset += shn->s.sh_size;
  325. #ifdef LITTLEENDIAN
  326.   shn->s.sh_size = l2bw(shn->s.sh_size);
  327. #endif
  328.  
  329.   /* ".strtab" string table */
  330.   shn = addShdr(&shdrlist);
  331.   shn->s.sh_name = ECVW(strtabidx);
  332.   shn->s.sh_type = ECW(SHT_STRTAB);
  333.   shn->s.sh_offset = ECVW(soffset);
  334.   shn->s.sh_size = ECVW(strlist.index);
  335.   shn->s.sh_addralign = ECW(1);
  336.   soffset += strlist.index;
  337.   align2 = ((soffset + 3) & ~3) - soffset;
  338.   soffset += align2;  /* offset for first Rela-entry */
  339.  
  340.   /* create output file */
  341.   if (fp = fopen(output_name,"wb")) {
  342.     struct StrTabNode *stn;
  343.     struct RelaNode *rn;
  344.  
  345.     fw(fp,&elf_header,sizeof(struct Elf32_Ehdr));  /* write header */
  346.  
  347.     /* write initialized section contents */
  348.     sec = (struct Section *)gv->sectionlist.first;
  349.     while (nextsec = (struct Section *)sec->n.next) {
  350.       if (!(sec->flags & (SF_DISCARD|SF_UNINITIALIZED)))
  351.         fw(fp,sec->contents,sec->size);
  352.       sec = nextsec;
  353.     }
  354.  
  355.     /* write comment section */
  356.     if (gv->ident || gv->vc) {
  357.       fw(fp,gv->alignment_bytes,1);  /* write leading 0-byte */
  358.       if (gv->ident)
  359.         fw(fp,gv->ident,strlen(gv->ident)+1);
  360.       if (gv->vc) {
  361.         uint32 v = ECW(0x16020303);
  362.  
  363.         fw(fp,&v,4);
  364.         v = ECVW((uint32)time(NULL));
  365.         fw(fp,&v,4);
  366.         v = ECW(0x03030216);
  367.         fw(fp,&v,4);
  368.       }
  369.     }
  370.  
  371.     /* write .shstrtab string table */
  372.     while (stn = (struct StrTabNode *)remhead(&shstrlist.l))
  373.       fw(fp,stn->str,strlen(stn->str)+1);
  374.  
  375.     /* write section headers */
  376.     fw(fp,gv->alignment_bytes,align1);
  377.     while (shn = (struct ShdrNode *)remhead(&shdrlist)) {
  378.       if (shn->s.sh_type == ECW(SHT_RELA)) {
  379.         /* set correct offset */
  380.         shn->s.sh_offset = ECVW(shn->s.sh_offset + soffset);  
  381.         shn->s.sh_link = ECVW(shdrindex); /* index of associated symbol table */
  382.       }
  383.       fw(fp,&(shn->s),sizeof(struct Elf32_Shdr));
  384.     }
  385.  
  386.     /* write symbol table */
  387.     while (sym = (struct SymbolNode *)remhead(&symlist))
  388.       fw(fp,&(sym->s),sizeof(struct Elf32_Sym));
  389.  
  390.     /* write .strtab string table */
  391.     while (stn = (struct StrTabNode *)remhead(&strlist.l))
  392.       fw(fp,stn->str,strlen(stn->str)+1);
  393.  
  394.     /* write relocations */
  395.     fw(fp,gv->alignment_bytes,align2);
  396.     while (rn = (struct RelaNode *)remhead(&relalist))
  397.       fw(fp,&(rn->r),sizeof(struct Elf32_Rela));
  398.  
  399.     fclose(fp);
  400.   }
  401.   else
  402.     error(25,output_name);  /* unable to create output file */
  403. }
  404.  
  405.  
  406. static struct ShdrNode *addShdr(struct list *l)
  407. {
  408.   struct ShdrNode *s = alloczero(sizeof(struct ShdrNode));
  409.  
  410.   addtail(l,&(s->n));
  411.   return (s);
  412. }
  413.  
  414.  
  415. static struct SymbolNode *addSymbol(struct list *l,struct StrTabList *sl,
  416.                                     char *name)
  417. {
  418.   struct SymbolNode *sn = alloczero(sizeof(struct SymbolNode));
  419.  
  420.   addtail(l,&(sn->n));
  421.   if (name) {
  422.     sn->name = name;
  423.     sn->s.st_name = ECVW(addString(sl,name));
  424.   }
  425.   return (sn);
  426. }
  427.  
  428.  
  429. static uint32 addString(struct StrTabList *sl,char *s)
  430. {
  431.   struct StrTabNode *sn = alloc(sizeof(struct StrTabNode));
  432.   uint32 idx = sl->index;
  433.  
  434.   sn->str = s;
  435.   addtail(&(sl->l),&(sn->n));
  436.   sl->index += (uint32)strlen(s) + 1;
  437.   return (idx);
  438. }
  439.  
  440.  
  441. static void addRela(struct list *l,uint32 o,uint32 a,uint32 i)
  442. {
  443.   struct RelaNode *rn = alloc(sizeof(struct RelaNode));
  444.  
  445.   rn->r.r_offset = ECVW(o);
  446.   rn->r.r_addend = ECVW(a);
  447.   rn->r.r_info = ECVW(i);
  448.   addtail(l,&(rn->n));
  449. }
  450.  
  451.  
  452. static void fw(FILE *fp,void *buf,size_t len)
  453. {
  454.   if (len) {
  455.     if (!fwrite(buf,1,len,fp)) {
  456.       fclose(fp);
  457.       error(26,output_name);  /* write error */
  458.     }
  459.   }
  460. }
  461.